package com.cloudfun.campusshare.device.protocol.handler;

import cn.hutool.core.bean.BeanUtil;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.DeviceType;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.DeviceCsqDTO;
import com.cloudfun.campusshare.device.protocol.command.CheckDeviceStatus;
import com.cloudfun.campusshare.device.protocol.command.Frame;
import com.cloudfun.campusshare.device.protocol.command.PumpFrame;
import com.cloudfun.campusshare.device.protocol.consumer.DeviceMessageConsumer;
import com.cloudfun.campusshare.device.protocol.decoder.Decoder;
import com.cloudfun.campusshare.device.protocol.decoder.PumpDecoder;
import com.cloudfun.campusshare.device.protocol.response.BaseMessage;
import com.cloudfun.campusshare.repo.DeviceEntityRepo;
import com.cloudfun.campusshare.service.DeviceCsqService;
import com.cloudfun.campusshare.service.DeviceService;
import com.cloudfun.campusshare.service.ResponseMessageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Component;

import javax.jms.JMSException;
import javax.jms.Message;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Created by Huqin on 2020/3/25
 */
@Slf4j
@Component
public class AliyunIotDeviceMsgHandler implements AliyunIotMsgHandler {

    @Autowired
    private List<DeviceMessageConsumer> deviceMessageConsumers;

    @Autowired
    private ResponseMessageService responseMessageService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private DeviceCsqService deviceCsqService;

    @Autowired
    private DeviceEntityRepo deviceEntityRepo;

    @Override
    public boolean support(Message message) throws JMSException {
        return message.getStringProperty("topic").endsWith("user/update");
    }

    @Override
    public void handle(Message message) throws JMSException {
        String topic = message.getStringProperty("topic");
        String messageId = message.getStringProperty("messageId");
        String timestamp = message.getStringProperty("generateTime");
        String[] split = topic.split("/");
        String deviceName = split[2];

        String deviceType = deviceService.getDeviceType(deviceName);
        if (StringUtils.isBlank(deviceType)) {
            log.error("没有设备数据或没有设备类型：{}", deviceName);
            return;
        }
        DeviceType deviceTypeByName = DeviceType.getDeviceTypeByName(deviceType);
        if (null == deviceTypeByName) {
            log.error("设备类型错误：{}", deviceType);
            return;
        }
        // 校验设备状态
//        CompletableFuture.runAsync(new CheckDeviceStatus(deviceEntityRepo,deviceName));

        byte[] body = message.getBody(byte[].class);
        List list = new ArrayList();
        // 洗衣机底板发上来的数据包都是FFFF开头的
        if(body[0] == -1 && body[1] == -1){
            list = Frame.parse(body);
        }else if(body[0] == PumpFrame.DEFAULT_HEAD || body[0] == PumpFrame.RESPONSE_DEFAULT_HEAD){
            // 液体泵发过来的数据头部为ee或者66
            list = PumpFrame.parse(body);
        }else{
            // csq
            this.consumeCsq(deviceName, timestamp, body);
        }
        log.debug("messageId: {}, 解析帧：{}", messageId, list);

        for (int i = 0; i < list.size(); i++) {
            messageId = messageId + "_" + i;
            boolean createSuccess = false;
            Object object = list.get(i);
            BaseMessage baseMessage = null;
            if(object instanceof Frame){
                createSuccess = responseMessageService.create(messageId, deviceType, deviceName, (Frame) list.get(i));
                baseMessage = Decoder.decode(((Frame) list.get(i)).getContent(), deviceTypeByName);
            }else if(object instanceof PumpFrame){
                createSuccess = responseMessageService.create(messageId, deviceType, deviceName, (PumpFrame) list.get(i));
                baseMessage = PumpDecoder.decode((PumpFrame) list.get(i));
            }
            if (!createSuccess) {
                log.debug("阿里云消息：{}，内容：{}已处理，不再处理", messageId, object);
                continue;
            }
            if(baseMessage != null){
                baseMessage.setTimestamp(timestamp);
                log.info("message: {}", BeanUtil.beanToMap(baseMessage));
                this.consumeDeviceMsg(baseMessage, deviceName, messageId);
            }
        }
    }

    private void consumeCsq(String deviceName, String timestamp, byte[] body) {
        // rrpc,getcsq,31
        String csqString = new String(body);
        log.info("csq message: {} from device: {}", csqString, deviceName);
        Integer csq = Integer.valueOf(csqString.split(",")[2]);
        DeviceCsqDTO deviceCsqDTO = new DeviceCsqDTO();
        deviceCsqDTO.setImei(deviceName);
        deviceCsqDTO.setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timestamp)), ZoneId.systemDefault()));
        deviceCsqDTO.setCsq(csq);
        deviceCsqService.create(deviceCsqDTO);
    }

    private void consumeDeviceMsg(BaseMessage baseMessage, String deviceName, String messageId) {
        boolean processSuccess = false;
        for (int i = 0; i < 5; i++) {
            try {
                deviceService.updateInteractionTime(deviceName, baseMessage.getTimestamp());
                // 消费
                for (DeviceMessageConsumer deviceMessageConsumer : deviceMessageConsumers) {
                    if (deviceMessageConsumer.support(baseMessage.getClass())) {
                        deviceMessageConsumer.doConsumer(baseMessage, deviceName);
                    }
                }
                processSuccess = true;
                break;
            } catch (ObjectOptimisticLockingFailureException oplfe) {
                log.error("4G设备消息：{}, 处理时乐观锁异常", messageId, oplfe);
            }
        }
        if (!processSuccess) {
            throw new BusinessException(Code.ERROR, "乐观锁失败，且超过最大重试次数：" + 5);
        }
    }
}
